package com.bodu.global.config;

import com.bodu.global.config.filter.KaptchaAuthenticationFilter;
import com.bodu.global.config.filter.TokenAuthenticationFilterConfig;
import com.bodu.global.config.handler.FailHandler;
import com.bodu.global.config.handler.SuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * spring secuirty 配置
 *
 * @author gaoya
 * @date 2022 - 10 - 10 22:57:36
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    private final UserDetailsService userDetailsService;

    private final SuccessHandler successHandler;

    private final FailHandler failHandler;

    @Autowired
    private KaptchaAuthenticationFilter kaptchaAuthenticationFilter;


    /**
     * filter 使用
     *
     * @return TokenAuthenticationFilter
     */
    @Bean
    public TokenAuthenticationFilterConfig tokenAuthenticationFilter() {
        return new TokenAuthenticationFilterConfig();
    }

    public SpringSecurityConfig(UserDetailsService userDetailsService, FailHandler failHandler, SuccessHandler successHandler) {
        this.userDetailsService = userDetailsService;
        this.failHandler = failHandler;
        this.successHandler = successHandler;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        super.configure(web);
        web.ignoring().antMatchers(
                "/v2/api-docs",
                "/swagger-resources/configuration/ui",
                "/swagger-resources",
                "/swagger-resources/configuration/security",
                "/webjars/**",
                "/swagger-ui.html",
                "/druid.html"
        );
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 在认证用户名和密码之前，判断token
        http.addFilterBefore(tokenAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
        http.addFilterBefore(kaptchaAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);

        http.authorizeRequests()
                // 放行/login/in
                .antMatchers("/login/in").permitAll()
                .antMatchers("/project/getOneModel").permitAll()
                .antMatchers("/captcha/v1").permitAll()
                .antMatchers("/file/upload").permitAll()
                .antMatchers("/swagger-ui.html").anonymous()
                .antMatchers("/doc.html").anonymous()
                .antMatchers("/druid.html").anonymous()
                // 所有的请求都需要权限
                .anyRequest().authenticated()
                .and()
                //不通过Session获取SecurityContext
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                // 表单
                .formLogin()
                // 登录接口
                .loginProcessingUrl("/login/in")
                // username paramter
                .usernameParameter("username")
                // password paramter
                .passwordParameter("password")
                // 成功返回
                .successHandler(successHandler)
                // 失败返回
                .failureHandler(failHandler)
                .and()
                .csrf().disable()
        ;
    }
}
